import numpy as np
import matplotlib.pyplot as plt


class TS:
    def __init__(self, value_fun, t=2, q=4):
        """
        TS 算法框架，继承此类可快速完成算法细节
        value_fun:求值函数
        t:禁忌长度
        q:邻域半径
        flag:邻域类型
        """
        self.value_fun = value_fun
        self.t = t
        self.q = q
        self.tabu_list = {}
        self.best_value = []
        self.top = -1
        self.flag = 0

    def get_near_area(self, now, tabu_list: dict):
        """
        返回邻域下标
        """
        if self.flag == 0:
            min_sample = max(now-self.q, 0)
            max_sample = min(now+self.q, self.top)
            near_area = list(
                set(list(range(min_sample, max_sample)))-set(list(tabu_list.keys()))-{now})

        elif self.flag == 1:
            last = list(now)
            res = []
            for i in range(self.top-1):
                last[i], last[i+1] = last[i+1], last[i]

                res.append("".join(last))

            near_area = list(set(res)-set(tabu_list)-{now})

        else:
            raise ValueError("参数异常!!!")
        return near_area

    def update_tabu_list(self, tabu_list: dict, x):
        """
        更新 tabu_list
        """
        for it in list(tabu_list.keys()):
            tabu_list[it] -= 1
            if tabu_list[it] == 0:
                del tabu_list[it]
        tabu_list[x] = self.t

        return tabu_list

    def __call__(self, **kwds):
        """
        data:dict格式
        epoch:迭代次数
        """
        epoch = kwds['epoch']
        data = kwds['data']
        self.flag = kwds['flag']
        f_init = 10000
        self.top = len(data)

        x0 = kwds['x0']

        x_now = x0
        print("{:^4s}\t{:^4s}\t{:^16s}\t{:^16s}".format('x', 'f', 'tabu_list', 'N(x)'))
        for _ in range(epoch):
            f_now = self.value_fun(x_now)

            if f_now < f_init:
                self.best_value.append(f_now)

                f_init = f_now

            near_area = self.get_near_area(x_now, self.tabu_list)
            print("{:<4s}\t{:<4s}\t{:<16s}\t{:<16s}".format(str(x_now), str(f_now), str(self.tabu_list), str(near_area)))
            x_now = np.random.choice(near_area)

            self.tabu_list = self.update_tabu_list(self.tabu_list, x_now)

        print("*"*30)
        print("最优值为：{}".format(min(self.best_value)))
        plt.plot(self.best_value)

        plt.show()





datas={"1":[10,15,3,10],"2":[8,20,2,22],"3":[6,10,5,10],"4":[7,30,4,8]}
def value_fun(x):
    datass={"1":[10,15,3,10],"2":[8,20,2,22],"3":[6,10,5,10],"4":[7,30,4,8]}
    init_length=0
    xs=list(x)
    value=0

    for it in xs:
        workpiece=datass[it]
        init_length+=workpiece[0]
        

        t=workpiece[1]-init_length

        if t>0:
            value+=t*workpiece[2]

        else:
            value+=(-t*workpiece[3])

    return value
   


model=TS(value_fun=value_fun)

model(epoch=10,data=datas,flag=1,x0='1234')



